﻿using Microsoft.VisualStudio.DebuggerVisualizers;

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows;
using System.Windows.Media;

namespace DependencyObjectTreeViewer
{
    public class DependencyObjectObjectSource : VisualizerObjectSource
    {
        /// <summary>
        /// Serializes the DependencyObject.
        /// </summary>
        /// <param name="target">The DependencyObject to serialize.</param>
        /// <param name="outgoingData">The stream that can hold the serialized data.</param>
        public override void GetData(object target, Stream outgoingData)
        {
            DependencyObject depObj = (DependencyObject)target;

            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(outgoingData, new DependencyObjectData(WalkLogicalTree(depObj), WalkVisualTree(depObj)));
        }

        /// <summary>
        /// Walks the logical tree of elements.
        /// </summary>
        /// <param name="depObj">The DependencyObject to walk.</param>
        /// <returns>A serializable DependencyObjectTreeNode object holding the data.</returns>
        private DependencyObjectData.DependencyObjectTreeNode WalkLogicalTree(DependencyObject depObj)
        {
            DependencyObjectData.DependencyObjectTreeNode node = new DependencyObjectData.DependencyObjectTreeNode(depObj.DependencyObjectType.Name);

            foreach (object child in LogicalTreeHelper.GetChildren(depObj))
            {
                DependencyObject childDepObj = child as DependencyObject;

                // If this is a DependencyObject then traverse it's children
                if (childDepObj != null)
                    node.Children.Add(WalkLogicalTree(childDepObj));
                else
                    node.Children.Add(new DependencyObjectData.DependencyObjectTreeNode(child.GetType().ToString()));
            }

            return node;
        }

        /// <summary>
        /// Walks the visual tree of elements
        /// </summary>
        /// <param name="depObj">The DependencyObject to walk.</param>
        /// <returns>A serializable DependencyObjectTreeNode object holding the data.</returns>
        private DependencyObjectData.DependencyObjectTreeNode WalkVisualTree(DependencyObject depObj)
        {
            DependencyObjectData.DependencyObjectTreeNode node = new DependencyObjectData.DependencyObjectTreeNode(depObj.DependencyObjectType.Name);

            for (int i = 0, count = VisualTreeHelper.GetChildrenCount(depObj); i < count; i++)
            {
                DependencyObject childObj = VisualTreeHelper.GetChild(depObj, i);
                node.Children.Add(WalkVisualTree(childObj));
            }

            return node;
        }
    }
}